﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace System.Drawing
{
    /// <summary>
    /// This class provides a double-precision X/Y coordinate for lat/long
    /// </summary>
    [Serializable, ComVisible(true)]
    public struct PointD
    {
        private double _X;
        private double _Y;

        /// <summary>
        /// Represents a new instance of the System.Drawing.PointD class with member data left invalid.
        /// </summary>        
        public static PointD NaN
        {
            get { return new PointD(double.NaN, double.NaN); }
        }



        /// <summary>
        /// Represents a new instance of the System.Drawing.PointD class with member data left uninitialized.
        /// </summary>
        public static PointD Empty
        {
            get { return new PointD(0, 0); }
        }

   
        /// <summary>
        /// Initializes a new instance of the System.Drawing.PointD class with the specified coordinates.
        /// </summary>
        /// <param name="x">The horizontal position of the point.</param>
        /// <param name="y">The vertical position of the point.</param>
        public PointD(double x, double y)
        {
            _X = x;
            _Y = y;
        }

        /// <summary>
        /// Initialize a new System.Drawing.PointD based on a single-precision point
        /// </summary>
        /// <param name="InPoint"></param>
        public PointD(PointF InPoint)
        {
            _X = InPoint.X;
            _Y = InPoint.Y;
        }

        /// <summary>
        /// Convert a PointD to PointF
        /// </summary>
        /// <returns></returns>
        public PointF ToPointF()
        {
            return new PointF((float)this._X, (float)this._Y);
        }

   
        /// <summary>
        ///  Translates a System.Drawing.PointD by the negative of a given System.Drawing.Size.
        /// </summary>
        /// <param name="pt">A System.Drawing.PointD to compare.</param>
        /// <param name="sz">A System.Drawing.PointD to compare.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD operator -(PointD pt, Size sz)
        {
            return new PointD(pt.X - (double)sz.Width, pt.Y - (double)sz.Height);
        }


        /// <summary>
        /// Translates a System.Drawing.PointD by the negative of a specified System.Drawing.SizeF.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.SizeF that specifies the numbers to subtract from the coordinates of pt.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD operator -(PointD pt, SizeF sz)
        {
            return new PointD(pt.X - (double)sz.Width, pt.Y - (double)sz.Height);
        }

   
        /// <summary>
        /// Determines whether the coordinates of the specified points are not equal.
        /// </summary>
        /// <param name="left">A System.Drawing.PointD to compare.</param>
        /// <param name="right">A System.Drawing.PointD to compare.</param>
        /// <returns>true to indicate the System.Drawing.PointD.X and System.Drawing.PointD.Y values of left and right are not equal; otherwise, false.</returns>
        public static bool operator !=(PointD left, PointD right)
        {
            return left.X != right.X && left.Y != right.Y;
        }


        /// <summary>
        /// Translates a System.Drawing.PointD by a given System.Drawing.Size.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">A System.Drawing.Size that specifies the pair of numbers to add to the coordinates of pt</param>
        /// <returns>Returns the translated System.Drawing.PointD.</returns>
        public static PointD operator +(PointD pt, Size sz)
        {
            return new PointD(pt.X + (double)sz.Width, pt.Y + (double)sz.Height);
        }

    
        /// <summary>
        /// Translates the System.Drawing.PointD by the specified System.Drawing.SizeF.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.SizeF that specifies the numbers to add to the x- and y-coordinates of the System.Drawing.PointD.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD operator +(PointD pt, SizeF sz)
        {
            return new PointD(pt.X + (double)sz.Width, pt.Y + (double)sz.Height);
        }
        /// <summary>
        /// Compares two System.Drawing.PointD structures. The result specifies whether
        ///     the values of the System.Drawing.PointD.X and System.Drawing.PointD.Y properties
        ///     of the two System.Drawing.PointD structures are equal.
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static bool operator ==(PointD left, PointD right)
        {
            return left.X == right.X && left.Y == right.Y;
        }

        /// <summary>
        /// Gets a value indicating whether this System.Drawing.PointD is empty.
        /// </summary>
        [Browsable(false)]
        public bool IsEmpty
        {
            get { return _X == 0 && _Y == 0; }
        }

        /// <summary>
        /// Gets a value indicating whether this System.Drawing.PointD is empty.
        /// </summary>
        [Browsable(false)]
        public bool IsNan
        {
            get { return double.IsNaN(_X) && double.IsNaN(_Y); }
        }

         /// <summary>
        /// Gets or sets the x-coordinate of this System.Drawing.PointD.
        /// </summary>
        /// <returns>The x-coordinate of this System.Drawing.PointD.</returns>
        public double X
        {
            get { return _X; }
            set { _X = value; }
        }

          /// <summary>
        /// 
        /// </summary>
        /// <returns>Gets or sets the y-coordinate of this System.Drawing.PointD.</returns>
        public double Y
        {
            get { return _Y; }
            set { _Y = value; }
        }

        /// <summary>
        /// Translates a given System.Drawing.PointD by the specified System.Drawing.Size.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.Size that specifies the numbers to add to the coordinates of pt.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD Add(PointD pt, Size sz)
        {
            return new PointD(pt.X + (double)sz.Width, pt.Y + (double)sz.Height);
        }
       
        /// <summary>
        /// Translates a given System.Drawing.PointD by a specified System.Drawing.SizeF.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.SizeF that specifies the numbers to add to the coordinates of pt</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD Add(PointD pt, SizeF sz)
        {
            return new PointD(pt.X + (double)sz.Width, pt.Y + (double)sz.Height);
        }

        /// <summary>
        /// Specifies whether this System.Drawing.PointD contains the same coordinates as the specified System.Object.
        /// </summary>
        /// <param name="obj">The System.Object to test.</param>
        /// <returns>This method returns true if obj is a System.Drawing.PointD and has the same coordinates as this System.Drawing.Point.</returns>
        public override bool Equals(object obj)
        {
            if (obj is PointD == false)
                return false;
            else
                return (((PointD)obj).X == _X && ((PointD)obj)._Y == Y);
        }

        /// <summary>
        /// Returns a hash code for this System.Drawing.PointD structure.
        /// </summary>
        /// <returns>An integer value that specifies a hash value for this System.Drawing.PointD structure.</returns>
        public override int GetHashCode()
        {
            return X.GetHashCode() + Y.GetHashCode();
        }

            
        /// <summary>
        /// Translates a System.Drawing.PointD by the negative of a specified size.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.Size that specifies the numbers to subtract from the coordinates of pt.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD Subtract(PointD pt, Size sz)
        {
            return new PointD(pt.X - (double)sz.Width, pt.Y - (double)sz.Height);
        }

        
        
        /// <summary>
        /// Translates a System.Drawing.PointD by the negative of a specified size.
        /// </summary>
        /// <param name="pt">The System.Drawing.PointD to translate.</param>
        /// <param name="sz">The System.Drawing.SizeF that specifies the numbers to subtract from the coordinates of pt.</param>
        /// <returns>The translated System.Drawing.PointD.</returns>
        public static PointD Subtract(PointD pt, SizeF sz)
        {
            return new PointD(pt.X - (double)sz.Width, pt.Y - (double)sz.Height);
        }
   
        /// <summary>
        /// Converts this System.Drawing.PointD to a human readable string.
        /// </summary>
        /// <returns>A string that represents this System.Drawing.PointD.</returns>
        public override string ToString()
        {
            return _X.ToString() + "," + _Y.ToString();
        }
    }
}
